/*
 * ============================================================================
 *
 *       Filename:  IPRecordReader.cpp
 *
 *    Description:  implemention of IPRecordReader class and its derived classes
 *
 *         Author:  liangqing
 *
 * ============================================================================
 */
#include "IPRecordReader.h"
/*
 * Split a line with four parts:
 *  begin ip of an ip record (4 bytes, little endian)
 *  end ip of an ip record (4 bytes, little endian)
 *  the region of an ip record
 *  the section of an ip record (optional)
 * 
 * any space chars will be omitted except in the *section* part
 *
 * return 0 for success
 * return other for failure:
 * (missing any parts of the first three, or meet an invalid ipv4 address)
 *
 */
int IPRecordReader::split(const char *line, IPRecord *record) {
    int find, i, last;
    char *curr;
    unsigned char *ip;
    char *segs[4];
    int len[]={ sizeof(record->begin_ip), 
                sizeof(record->end_ip),
                sizeof(record->region),
                sizeof(record->section)};
    
    if(!(line && record)) return -1;
    
    segs[0] = (char*)record->begin_ip;
    segs[1] = (char*)record->end_ip;
    segs[2] = record->region;
    segs[3] = record->section;

    for(find=0; find < 4; find++){
        curr = segs[find];
        curr[0] = '\0';
        
        while(*line && is_space(*line) ) line++;
        if(!*line) break;
        
        i=0, last=0;

        if(find < 2){   //ip address
            ip = (unsigned char*) curr;
            if(!(line = str2ip(line, ip, len[find]))) return -2;
        }
        else {  //region or section
            while( *line && (find==3||!is_space(*line)) ) {
                if (i < len[find]){
                    curr[i] = *line;
                    if(!is_space(*line))
                        last = i==(len[find]-1)? i:(i+1);
                }
                i++;
                line++;
            }
            curr[last] = '\0';
        }
    }

    //less than three parts
    if(find < 3) return -3;

    return 0;
}

/*
 *  convert string ip to byte ip
 */
const char *IPRecordReader::str2ip(const char *str, unsigned char *ip, size_t size) {
    int i;
    memset(ip, 0, size);
    
    for(i=0; *str && i < 4; i++, str++){
        while(*str && *str!='.' && !is_space(*str)){
            if(!isdigit(*str)) return NULL;
            ip[3-i] = ip[3-i]*10 + (*str - '0');
            str++;
        }
        if(!*str || is_space(*str)) break;
    }
    
    return str;
}

IPRecordReaderQueue::IPRecordReaderQueue(const char *filters) {
    if(!filters || filters[0]=='\0') return;
    char *alloc = new char[strlen(filters) + 1];
    if(alloc == NULL) return;
    strcpy(alloc, filters);
    char *start = alloc;
    char *str = alloc;
    int length = 0;

    for(; *str ; ++str) {
        if(*str == '\n') {
            *str = '\0';
            if(length == 0) continue;
            _filters.push_back(start);
            start = str + 1;
            length = 0;
        }
        else {
            length++;
        }
    }
    if(length > 0)
        _filters.push_back(start);

    delete [] alloc;
}

IPRecordReaderQueue::~IPRecordReaderQueue(){
    IPRecordReader *pReader = NULL;
    
    while(!_queue.empty()) {
        pReader = _queue.front();
        if(pReader)
            delete pReader;
        _queue.pop_front();
    }
}

bool IPRecordReaderQueue::get(IPRecord *record) {
    return _get(record);
}

bool IPRecordReaderQueue::_get(IPRecord *record) {
    IPRecordReader *pReader;

    //FIFO
    while(!_queue.empty()) {
		pReader = _queue.front();
        if(pReader && pReader->get(record)) {
            if(!_filter_string(record))
                continue;
            return true;
        }
		if(pReader)
		    delete pReader;
        _queue.pop_front();
    }

    return false;
}

void IPRecordReaderQueue::push_reader(IPRecordReaderType type, const char *filename) {
    _push_reader(type, filename);
}

void IPRecordReaderQueue::_push_reader(IPRecordReaderType type, const char *filename) {
    IPRecordReader *pReader = NULL;
    
    switch(type){
      case textfile:
        pReader = new IPRecordTextfileReader(filename);
        break;
      case qqwry:
        break;
    }
    
    if(pReader)
        _queue.push_back(pReader);
}

bool IPRecordReaderQueue::_filter_string(IPRecord *record) {
    StringArray::iterator i;
    int j=0;
    char *name;
    char *names[2] = {record->region, record->section};
    
    for(i=_filters.begin(); i!=_filters.end(); ++i) {
       for(; j < 2; j++) {
            name = names[j];
            if(name[0] == '\0') continue;

            if((*i).at(0)=='-' || (*i).at(0)=='*') {
                String temp(name);
                String::size_type pos = temp.find((*i).c_str() + 1);
                if(pos != String::npos) {
                    if((*i).at(0) == '-') {
                        const char *t = temp.replace(pos, (*i).length()-1, "").c_str();
                        while(is_space(*t)) t++;
                        strcpy(name, t);
                    }
                    else {
                        name[0] = '\0';
                    }
                }
            }
            else if((*i).compare(name) == 0) {
                name[0] = '\0';
            }
        }
    }
    
    if(record->region[0] == '\0') {
        if(record->section[0] == '\0')
            return false;
        strncpy(record->region, record->section, sizeof(record->region)-1);
        record->section[0] = '\0';
    }
    
    return true;
}

/*
 *  get record
 *  return true for geting a valid record, else for no more record can be get
 */
bool IPRecordTextfileReader::get(IPRecord *record) {
    while(getline(_line, sizeof(_line))) {
        if(!isdigit(_line[0]) && !is_space(_line[0])) continue;
        if(split(_line, record)) continue;
        return true;
    }
    
    return false;
}

bool IPRecordTextfileReader::getline(char *line, int size) {
#ifdef USE_IFSTREAM
    return _textfile.getline(line, size);
#else
    return fgets(line, size, _textfile); 
#endif /* USE_IFSTREAM */
}

bool IPRecordQQWryReader::get(IPRecord *record) {
    return true;
}

